package com.globallogic.dmytro_zakharenko.university;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import com.globallogic.dmytro_zakharenko.university.enums.LessonNames;
import com.globallogic.dmytro_zakharenko.university.lessons.Lesson;
import com.globallogic.dmytro_zakharenko.university.person.Teacher;

public class Curriculum {
	
	private Set<Teacher> mTeachers;
	
	private ArrayList<Lesson> mFirstCourseLessons;
	private ArrayList<Lesson> mSecondCourseLessons;
	private ArrayList<Lesson> mThirdCourseLessons;
	
	private Set<Teacher> mFirstCourseTeachers;
	private Set<Teacher> mSecondCourseTeachers;
	private Set<Teacher> mThirdCourseTeachers;
	
	private final int mNumOfExamsForCourse = 4;
	
	/**
     * Constructor.
     *
     * @param teacher
	 * @throws Exception 
     */
	public Curriculum(Set<Teacher> teacher) {
		if (teacher != null) {
			this.mTeachers = teacher;
		} else {
			throw new RuntimeException("No teachers were setted. Please set teachers when create Curriculum obj.");
		}
		
		this.setLessonsForCourses();
		this.setTeachersForCourses();
		
		this.setExamsForLessons(mFirstCourseLessons);
		this.setExamsForLessons(mSecondCourseLessons);
		this.setExamsForLessons(mThirdCourseLessons);
		
		this.setSetOffForLessons(mFirstCourseLessons);
		this.setSetOffForLessons(mSecondCourseLessons);
		this.setSetOffForLessons(mThirdCourseLessons);
	}
	
	/**
     * set lessons for each of course
     */
	private void setLessonsForCourses() {
		ArrayList<Lesson> firstCourseLessons = new ArrayList<Lesson>();
		ArrayList<Lesson> secondCourseLessons = new ArrayList<Lesson>();
		ArrayList<Lesson> thirdCourseLessons = new ArrayList<Lesson>();
		
		int i = 0;
		try {
			LessonNames.getLessonsName().toString();
		} catch (NullPointerException e) {
			System.out.println("The lessons were not initialized. Initialize to default lessons.");
			LessonNames.setBasicLessons();
		}
		
		for (String ls : LessonNames.getLessonsName()) {
			if (ls.equalsIgnoreCase("1_Course")) {
				firstCourseLessons.add(new Lesson(LessonNames.getLessonsName()[i - 1]));
			} else if (ls.equalsIgnoreCase("2_Course")) {
				secondCourseLessons.add(new Lesson(LessonNames.getLessonsName()[i - 1]));
			} else if (ls.equalsIgnoreCase("3_Course")) {
				thirdCourseLessons.add(new Lesson(LessonNames.getLessonsName()[i - 1]));
			}
			i++;
		}
 		
		this.mFirstCourseLessons = firstCourseLessons;
		this.mSecondCourseLessons = secondCourseLessons;
		this.mThirdCourseLessons = thirdCourseLessons;
	}
	
	/**
     * get lessons for the first course
     * 
     * * @return mFirstCourseLessons
     */
	public ArrayList<Lesson> getFirstCourseLessons() {
		return mFirstCourseLessons;
	}
	
	/**
     * get lessons for the second course
     * 
     * @return mSecondCourseLessons
     */
	public ArrayList<Lesson> getSecondCourseLessons() {
		return mSecondCourseLessons;
	}
	
	/**
     * get lessons for the third course
     * 
     * @return mThirdCourseLessons
     */
	public ArrayList<Lesson> getThirdCourseLessons() {
		return mThirdCourseLessons;
	}
	
	/**
     * set teachers for each of course
	 * @throws Exception 
     */
	private void setTeachersForCourses() {
		Set<Teacher> firstCourseTeachers  = new HashSet<Teacher>();
		Set<Teacher> secondCourseTeachers = new HashSet<Teacher>();
		Set<Teacher> thirdCourseTeachers  = new HashSet<Teacher>();
		
		int i = 0;
		int j = 0;
		int k = 0;
		String[] ls = LessonNames.getLessonsName();
		
		Teacher[] teacherArray = mTeachers.toArray(new Teacher[0]);
		for (Teacher t : teacherArray) {
			if (t.getLessons() == null) {
				throw new RuntimeException("No lessons were setted for teacher - " + t.getFirstName() + ". Please set lessons before invoking of this method.");
			}
			for (String les : t.getLessons()) {
				for (int p = 0; p < ls.length; p++) {
					if (les.equalsIgnoreCase(ls[p])) {
						if (ls[p + 1].equalsIgnoreCase("1_Course")) {
							if (!firstCourseTeachers.contains(t.getFirstName())) {
								firstCourseTeachers.add(teacherArray[i++]);
							}	
						} else if (ls[p + 1].equalsIgnoreCase("2_Course")) {
							if (!secondCourseTeachers.contains(t.getFirstName())) {
								secondCourseTeachers.add(teacherArray[j++]);
							}
						} else if (ls[p + 1].equalsIgnoreCase("3_Course")) {
							if (!thirdCourseTeachers.contains(t.getFirstName())) {
								thirdCourseTeachers.add(teacherArray[k++]);
							}	
						}
					}
				}	
			}
		}
		
		this.mFirstCourseTeachers  = firstCourseTeachers;
		this.mSecondCourseTeachers = secondCourseTeachers;
		this.mThirdCourseTeachers  = thirdCourseTeachers;		
	}
	
	/**
     * get teachers for the first course
     * 
     * @return mFirstCourseTeachers
     */
	public Set<Teacher> getFirstCourseTeachers() {
		return mFirstCourseTeachers;
	}
	
	/**
     * get teachers for the second course
     * 
     * @return mSecondCourseTeachers
     */
	public Set<Teacher> getSecondCourseTeachers() {
		return mSecondCourseTeachers;
	}
	
	/**
     * get teachers for the third course
     * 
     * @return mThirdCourseTeachers
     */
	public Set<Teacher> getThirdCourseTeachers() {
		return mThirdCourseTeachers;
	}
	
	/**
     * set SetOff for user specified lessons
     * 
     * @param lessonsOfCourse
     */
	private void setSetOffForLessons(ArrayList<Lesson> lessonsOfCourse) {
		if (lessonsOfCourse == null) {
			throw new RuntimeException("setSetOffForLessons() method can't take null as argument");
		}
		
		for (Lesson l : lessonsOfCourse) {
			if (!l.ismExamination()) {
				l.setmSetOff();
			}
		}
	}
	
	/**
     * set Exams for user specified lessons
     * 
     * @param lessonsOfCourse
     */
	private void setExamsForLessons(ArrayList<Lesson> lessonsOfCourse) {
		int count = 0;
		if (lessonsOfCourse == null) {
			throw new RuntimeException("setExamsForLessons() method can't take null as argument");
		}
		
		for (Lesson l : lessonsOfCourse) {
			if (Curriculum.getRandomBoolean() && count != this.mNumOfExamsForCourse) {
				l.setmExamination();
				count++;
			}
		}
	}
	
	private static boolean getRandomBoolean() {
	    return Math.random() < 0.5;
	}
	
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		} 
		if (!(other instanceof Curriculum)) {
			return false;
		}
		
		Curriculum otherA = (Curriculum) other;
		
		boolean result = true;
		java.util.Iterator<Lesson> targetIT =  (otherA.mFirstCourseLessons).iterator();
		for (Lesson firstCourseLesson : mFirstCourseLessons) {
			if (!firstCourseLesson.equals(targetIT.next())) {
				result = false;
				break;
			}
		}
		
		boolean result1 = true;
		java.util.Iterator<Teacher> targetIT1 =  otherA.mTeachers.iterator();
		for (Teacher teacher : mTeachers) {
			if (!teacher.equals(targetIT1.next())) {
				result1 = false;
				break;
			}
		}
		
		return ( result && result1 );
	}
	
	public int hashCode() {
		int result = 0;
		
		for (Teacher t : mTeachers) {
			result += t.hashCode(); 
		}
		
		for (Lesson l : mFirstCourseLessons) {
			result += l.hashCode(); 
		}
		
		return result;
	}
	
	public String toString() {
		return ("The Curriculum have : " + "Number Of teachers : " + this.getFirstCourseTeachers().size() + "Number Of lessons: " 
				+ this.getFirstCourseLessons() + this.getSecondCourseLessons() + this.getThirdCourseLessons());
	}
}
